using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;


namespace InventorySystem
{
    public class Inventory : MonoBehaviour
    {
        [SerializeField]
        private int _size = 8;

        [SerializeField]
        private List<InventorySlot> _slots;

        private int _activeSlotIdex;

        public int Size => _size;
        public List<InventorySlot> Slots => _slots;

        public int ActiveSlotIdex 
        {
            get => _activeSlotIdex;
            private set
            {
                _slots[_activeSlotIdex].Active = false;
                _activeSlotIdex = value < 0 ? _size - 1 : value % Size;
                _slots[_activeSlotIdex].Active = true;
            }
        }

        private void Awake()
        {
            if (_size > 0) 
            {
                _slots[0].Active = true;
            }
        }

        private void OnValidate()
        {
            AdjustSize();
        }

        private void AdjustSize() 
        {
            _slots ??= new List<InventorySlot>();
            if (_slots.Count > _size) _slots.RemoveRange(_size,_slots.Count - _size);
            if (_slots.Count < _size) _slots.AddRange(new InventorySlot[_size - _slots.Count]);
        
        }

        public bool IsFull()
        {
            return _slots.Count(slot => slot.HasItem) >= _size;
        }

        public bool CanAcceptItem(ItemStack itemStack) 
        {
            var slotWithStackableItem = FindSlot(itemStack.Item,true);
            return !IsFull() || slotWithStackableItem != null;
        }

        private InventorySlot FindSlot(ItemDifinition item,bool onlyStackable = false) 
        {
            return _slots.FirstOrDefault(slot => slot.Item == item && 
                                                   (item.IsStackable|| 
                                                   !onlyStackable));
        }

        public bool HasItem(ItemStack itemStack,bool chekNumberOfItems = false)
        {
            var itemSlot = FindSlot(itemStack.Item);
            if (itemSlot == null) return false;
            if (!chekNumberOfItems)
            {
                return true;
            }
            if (itemStack.Item.IsStackable)
            {
                return itemSlot.NuberOfItens >= itemStack.NumberOfItems;
            }
            else
            {
                return _slots.Count(slot => slot.Item == itemStack.Item) >= itemStack.NumberOfItems;
            }
        }

        public ItemStack AddItem(ItemStack itemStack) 
        {
            var relevantSlot = FindSlot(itemStack.Item,true);
            if (IsFull() && relevantSlot == null) 
            {
                throw new InventoryException(InventoryOperation.Add, "Inventory is Full");
            }

            if (relevantSlot != null)
            {
                relevantSlot.NuberOfItens += itemStack.NumberOfItems;
            }
            else 
            {
                relevantSlot = _slots.First(slot => !slot.HasItem);
                relevantSlot.State = itemStack;
            }

            return relevantSlot.State;


        }

        public ItemStack RemoveItem(int atIndex,bool spawn = false) 
        {
            if (!_slots[atIndex].HasItem) 
                throw new InventoryException(InventoryOperation.Remove, "slot is Empty");

            if (spawn && TryGetComponent<GameItemSpawner>(out var itemSpawner)) 
            {
                itemSpawner.SpawnItem(_slots[atIndex].State);
            }

            ClearSlot(atIndex);
            return new ItemStack(); 
        }

        public ItemStack RemoveItem(ItemStack itemStack) 
        {
            var itemSlot = FindSlot(itemStack.Item);
            if (itemSlot == null) 
            {
                throw new InventoryException(InventoryOperation.Remove, "No item in the inventory");
            }
            if(itemSlot.Item.IsStackable && itemSlot.NuberOfItens < itemStack.NumberOfItems)
                throw new InventoryException(InventoryOperation.Remove, "Not enough Items");

            itemSlot.NuberOfItens -= itemStack.NumberOfItems;
            if (itemSlot.Item.IsStackable && itemSlot.NuberOfItens > 0) 
            {
                return itemSlot.State;
            }

            itemSlot.Clear();
            return new ItemStack();

        }


        public void ClearSlot(int atIndex) 
        {
            _slots[atIndex].Clear();
        }

        public void ActivateSlot(int atIndex) 
        {
            ActiveSlotIdex = atIndex;
        }

        public InventorySlot GetInventorySlot() 
        {
            return _slots[ActiveSlotIdex];
        }

    }
}